package utils

import (
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
	"sync"
	"time"
)

// session 常用操作工具
// 使用 Builder 模式+单例模式
type SessionUtil struct {
	// 增加查看有哪些用户在线 map容器 todo 学习示例可以定义用户存放容器，真实开发不能这样写，应该是加解密session,或者redis
	coo map[string]interface{}
	mx  sync.RWMutex
}

// SessionContext session上下文，绑定特定请求
type SessionContext struct {
	session sessions.Session
	util    *SessionUtil
}

var (
	sessionUtilInstance *SessionUtil
	sessionUtilOnce     sync.Once
)

func GetSessionUtil() *SessionUtil {
	sessionUtilOnce.Do(func() {
		sessionUtilInstance = &SessionUtil{
			coo: make(map[string]interface{}),
		}
	})
	return sessionUtilInstance
}

// Use 创建绑定到特定请求的session上下文
func (this *SessionUtil) Use(c *gin.Context) *SessionContext {
	return &SessionContext{
		session: sessions.Default(c),
		util:    this,
	}
}

// 获取 session值
func (this *SessionContext) get(key string) interface{} {

	return this.session.Get(key)
}

// 获取所有keys
func (this *SessionContext) GetAll() []string {
	var keys []string = make([]string, 0, len(this.util.coo))
	for k, _ := range this.util.coo {
		keys = append(keys, k)
	}

	return keys
}

// 校验携带的 auth_session 是否存在map中
func (this *SessionContext) CheckAll(key string) error {

	for _, v := range this.util.coo {
		if key == v {
			return nil
		}
	}

	return fmt.Errorf("会话失效!")
}

// 设置  session值
func (this *SessionContext) SetKey(key string) (string, error) {
	val := this.Generate(16)

	// 加锁
	this.util.mx.Lock()
	defer this.util.mx.Unlock()

	// 存储值
	this.util.coo[key] = val

	// session 赋值
	this.session.Set(key, val)
	if err := this.session.Save(); err != nil {
		return "", err
	}

	return val, nil
}

// 设置  session值
func (this *SessionContext) Set(key string, val interface{}) error {
	// 加锁
	this.util.mx.Lock()
	defer this.util.mx.Unlock()

	// 存储值
	this.util.coo[key] = val

	// session 赋值
	this.session.Set(key, val)
	if err := this.session.Save(); err != nil {
		return err
	}

	return nil
}

// 删除  session值
func (this *SessionContext) Del(key string) error {
	// 加锁
	this.util.mx.Lock()
	defer this.util.mx.Unlock()

	// 从容器中删除
	delete(this.util.coo, key)

	// session 删除
	this.session.Delete(key)
	if err := this.session.Save(); err != nil {
		return err
	}

	return nil
}

// 删除所有  session值
func (this *SessionContext) Clear() error {
	// 加锁
	this.util.mx.Lock()
	defer this.util.mx.Unlock()

	// 重新赋值容器
	this.util.coo = make(map[string]interface{})

	// session 删除all
	this.session.Clear()
	if err := this.session.Save(); err != nil {
		return err
	}
	return nil
}

// 获取 int类型 session值
func (this *SessionContext) GetInt(key string) int {
	if val := this.get(key); val != nil {
		if v, ok := val.(int); ok {
			return v
		}
	}
	return 0
}

// 获取 string类型 session值
func (this *SessionContext) GetString(key string) string {
	if val := this.get(key); val != nil {
		if v, ok := val.(string); ok {
			return v
		}
	}
	return ""
}

// 内部方法：生成随机 session
func (this *SessionContext) Generate(length int) string {

	bytes := make([]byte, length)
	_, err := rand.Read(bytes)
	if err != nil {
		// 如果随机数生成失败，使用时间戳作为备选方案
		return fmt.Sprintf("%d", time.Now().UnixNano())
	}
	return hex.EncodeToString(bytes)
}

func test() {

	/*// 使用示例：
	func sessionHandler(c *gin.Context) {
		// 获取SessionUtil单例实例并绑定到当前请求
		sessionCtx := utils.GetSessionUtil().Use(c)

		// 设置session
		sessionCtx.Set("username", "john")
		sessionCtx.Set("age", 25)

		// 获取session
		username := sessionCtx.GetString("username")
		age := sessionCtx.GetInt("age")

		// 删除session
		sessionCtx.Delete("username")

		c.JSON(200, gin.H{
			"username": username,
			"age":      age,
		})
	}*/
}
